package com.link.base.base.email.service;

import com.alibaba.fastjson.JSONObject;
import com.link.base.base.alert.model.AlertObjField;
import com.link.base.base.alert.model.AlertObjType;
import com.link.base.base.alert.service.AlertObjFieldService;
import com.link.base.base.alert.service.AlertObjTypeService;
import com.link.base.base.email.dao.mybatis.mapper.EmailItemMapper;
import com.link.base.base.email.dao.mybatis.mapper.EmailMapper;
import com.link.base.base.email.emailutils.SendMail;
import com.link.base.base.email.model.EmailInfo;
import com.link.base.base.email.model.EmailItem;
import com.link.base.base.email.model.EmailReceiver;
import com.link.base.user.model.CoreUser;
import com.link.core.basic.dao.KeyGenerateDao;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.interceptor.SecurityInterceptor;
import com.link.core.basic.model.BasicModel;
import com.link.core.basic.query.Filter;
import com.link.core.basic.query.QueryParams;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.ServiceException;
import com.link.core.cllog.LCLogger;
import com.link.core.util.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;

/**
 * 邮件相关服务
 * @author unknwon
 * @version 1.0
 * @date: 2018/11/12 9:41
 */

@Service
public class EmailServiceImpl extends BasicServiceImpl<EmailInfo> implements EmailService {

    @Resource
    private EmailMapper emailMapper;
    @Resource
    private EmailItemMapper emailItemMapper;
    @Resource
    private KeyGenerateDao keyGenerateDao;

    @Resource
    private AlertObjTypeService alertObjTypeService;

    @Resource
    private AlertObjFieldService alertObjFieldService;

    @Resource
    private EmailItemService emailItemService;

    @Resource
    private EmailReceiverService emailReceiverService;

    @Resource
    private RestTemplate restTemplate;

    @Override
    public BasicMapper<EmailInfo> getBasicMapper() {
        return emailMapper;
    }

    @Override
    public void sendEmailByTemplate(EmailInfo emailInfo) throws Exception {
        /**
         * 1.根据传入的邮件id 查询到邮件模板信息
         * 2.根据模板信息中的查找到适配请求对象id 查找到对应的请求地址以及请求参数等信息
         * 3.设置规则将请求得到的信息匹配当前模板
         * 4.获取需要发送的用户信息
         * 5.发送邮件
         * 6.记录信息
         */
        LCLogger.info().withMessage("传入的参数信息：").flush();
        String title = "";
        String content = "";
        Map<String, String> emailReceiver = new HashMap<>();
        try {
            // 第1步
            Object params = emailInfo.getParams();
            List<String> filePaths = emailInfo.getFilePaths();
            emailInfo = this.queryById(emailInfo);
            emailInfo.setParams(params);
            emailInfo.setFilePaths(filePaths);
            if (!"Y".equals(emailInfo.getStatus())) {
                throw new Exception("该邮件模板已失效，请联系管理员");
            }

            //调用base的内部登录接口
            String userName = PropertyUtil.getCommonProperty("mock_unlogin_user");
            if (StringUtils.isBlank(userName)) {
                throw new Exception("默认登录用户名不存在");
            }
            TokenUtils.setLogin(userName);

            String token = SecurityInterceptor.INTERNAL_TOKEN.concat(":").concat(userName);
            // 第2步 目前仅支持一个对象 后续考虑支持多对象
            List<Map<String, Object>> objInfo = getObjInfo(emailInfo, token);
            LCLogger.info().withMessage("查询到的插入对象信息：" + JSONObject.toJSONString(objInfo)).flush();
            //获取对象的字段信息
            Map<String, String> fields = getObjField(emailInfo);
            LCLogger.info().withMessage("查询到的插入对象字段：" + JSONObject.toJSONString(fields)).flush();
            // 第3步 将请求得到的信息匹配到模板上面， 目前仅支持text 后续支持循环的html模板
            title = genEmailTitle(objInfo, fields, emailInfo);
            content = genEmailContent(objInfo, fields, emailInfo);

            // 第4步 获取需要发送的用户邮箱信息
            emailReceiver = getEmailReceiver(emailInfo);
            // 第五步 发送邮件
            sendEmail(emailReceiver, title, content, emailInfo);
            record(emailInfo, emailReceiver, title, content, null);
        } catch (Exception e) {
            // 记录日志信息
            record(emailInfo, emailReceiver, title, content, e);
            LCLogger.withException(e);
            throw new Exception(e);
        }
    }

    /**
     * 发送邮件
     *
     * @param entity
     * @return
     * @throws
     * @author yipeng.zhu@hand-china.com
     * @date 2019/2/21 10:18
     * @version 1.0
     */
    @Override
    @Transactional(rollbackFor = BasicServiceException.class)
    public void sendMail(EmailInfo entity) throws Exception {
        Map<String, String> sendMap = new HashMap<>(16);
        //邮件模板新信息
        EmailInfo emailInfo = emailMapper.queryById(entity);

        sendMap.put("emailAuthSecret", emailInfo.getEmailKey());
        sendMap.put("from", emailInfo.getEmailAddr());
        //邮件接收者信息

        List<EmailInfo> emailInfos = queryList(emailInfo);
        if (emailInfos == null || emailInfos.isEmpty()) {
            throw new ServiceException("EMAIL-001");
        }
        sendMap.put("subject", emailInfo.getEmailTitle());
        sendMap.put("body", emailInfo.getEmailMsg());
        List<File> fileList = entity.getFileList();

        Map<String, String> images = new HashMap<>(16);
        //网易
        String wyType = "NetEase";
        //腾讯qq
        String qqType = "Tencent";
        //添加接收邮件地址
        List<String> addrList = new ArrayList<>();
        if (wyType.equals(emailInfo.getEmailSource())) {
            sendMap.put("smtp", "smtp.163.com");
            //邮件发送至发件人 反垃圾邮件机制
            addrList.add(emailInfo.getEmailAddr());
        }
        for (EmailInfo bean : emailInfos) {
            addrList.add(bean.getEmailAddr());
        }
        StringBuilder sb = new StringBuilder();
        for (String str : addrList) {
            sb.append(",").append(str);
        }
        String addrStr = sb.substring(1);
        if (qqType.equals(emailInfo.getEmailSource())) {
            sendMap.put("smtp", "smtp.qq.com");
        }
        sendMap.put("to", addrStr);
        SendMail email = new SendMail(sendMap,fileList);
        //插入发送邮件记录
        insetSendRecord(emailInfo, emailInfos);
        if (wyType.equals(emailInfo.getEmailSource())) {
            email.sendNetEaseMail();
        }
        if (qqType.equals(emailInfo.getEmailSource())) {
            email.sendQqMail();
        }

    }

    /**
     * 插入邮件发送记录
     * @author yipeng.zhu@hand-china.com
     * @param email         邮件模板信息
     * @param emailInfoList 邮件接收者信息
     * @return
     * @throws
     * @date 2019/2/21 10:16
     * @version 1.0
     */
    public void insetSendRecord(EmailInfo email, List<EmailInfo> emailInfoList) throws Exception {
        CoreUser loginUser = UserUtil.getUser();
        for (EmailInfo bean : emailInfoList) {
            EmailItem insert = new EmailItem();
            insert.setId(keyGenerateDao.keyGenerate());
            insert.setStatus("TO_SEND");
            insert.setEmailId(email.getId());
            insert.setEmailReceiveAddr(bean.getEmailAddr());
            insert.setEmailContent(email.getEmailMsg());
            insert.setCorpid(loginUser.getCorpid());
            emailItemMapper.insert(insert);
        }
    }

    /**
     * 通过模板编码 查询相关接受接邮件者的信息
     * @author yipeng.zhu@hand-china.com
     * @param entity
     * @return
     * @throws
     * @date 2019/2/21 10:17
     * @version 1.0
     */
    public List<EmailInfo> queryList(EmailInfo entity) throws Exception {
        QueryParams queryParams = new QueryParams();
        queryParams.addFilter(new Filter("emailSource", Filter.OP_EQUAL, entity.getEmailCode()));
        queryParams.setPageFlag(false);
        EmailInfo query = (EmailInfo) BasicModel.transformClass(EmailInfo.class, queryParams);
        List<EmailInfo> queryList = emailMapper.queryByExamplePage(query);
        return queryList;
    }

    public void sendEmail(Map<String, String> emailReceiver, String title, String content, EmailInfo emailInfo) throws Exception {
        if (StringUtils.isBlank(title)) {
            throw new Exception("不存在邮件标题");
        }
        if (StringUtils.isBlank(content)) {
            throw new Exception("不存在邮件正文");
        }
        com.link.core.basic.model.EmailInfo tempEmailInfo = new com.link.core.basic.model.EmailInfo();
        String protocol = PropertyUtil.getCommonProperty("protocol");
        String host = PropertyUtil.getCommonProperty("host");
        String port = PropertyUtil.getCommonProperty("port");
        String username = PropertyUtil.getCommonProperty("adress_bk");
        String password = PropertyUtil.getCommonProperty("password_bk");
        String from = PropertyUtil.getCommonProperty("adress_bk");
        if (StringUtils.isNotBlank(protocol)) {
            tempEmailInfo.setProtocol(protocol);
        }
        if (StringUtils.isBlank(host)) {
            throw new Exception("不存在邮件服务器地址，请联系管理员");
        }
        tempEmailInfo.setHost(host);

        if (StringUtils.isBlank(port)) {
            throw new Exception("不存在邮件服务器端口，请联系管理员");
        }
        tempEmailInfo.setPort(port);

        if (StringUtils.isBlank(username)) {
            throw new Exception("不存在邮件服务器认证用户，请联系管理员");
        }
        tempEmailInfo.setUsername(username);

        if (StringUtils.isBlank(password)) {
            throw new Exception("不存在邮件服务器认证密码，请联系管理员");
        }
        tempEmailInfo.setPassword(password);

        if (StringUtils.isBlank(from)) {
            throw new Exception("不存在发送邮箱，请联系管理员");
        }
        tempEmailInfo.setFrom(from);

        tempEmailInfo.setTo(emailReceiver.get("to"));
        if (StringUtils.isNotBlank(emailReceiver.get("toCc"))) {
            tempEmailInfo.setToCc(emailReceiver.get("toCc"));
        }
        tempEmailInfo.setSubject(title);
        tempEmailInfo.setContent(content);
        tempEmailInfo.setContentType("Text".equals(emailInfo.getTemplateType()) ? "text" : "html");
        if (emailInfo.getFilePaths() != null && emailInfo.getFilePaths().size() > 0) {
            tempEmailInfo.setAttachment(emailInfo.getFilePaths());
        }
        EmailUtil.send(tempEmailInfo);
    }


    public Map<String, String> getEmailReceiver(EmailInfo emailInfo) throws Exception {
        Map<String, String> map = new HashMap<>();
        QueryParams qps = new QueryParams();
        qps.setPageFlag(false);
        qps.addFilter(new Filter("headId", String.valueOf(emailInfo.getId())));
        qps.addFilter(new Filter("receiverStatus", "Y"));
        EmailReceiver t = (EmailReceiver) BasicModel.transformClass(new EmailReceiver(), qps);
        List<EmailReceiver> emailReceivers = emailReceiverService.queryByExamplePage(t);
        if (emailReceivers == null || emailReceivers.size() <= 0) {
            throw new Exception("不存在收件人");
        }
        // 主收件人
        StringBuilder to = new StringBuilder();
        // 抄送人
        StringBuilder toCc = new StringBuilder();

        for (EmailReceiver emailReceiver : emailReceivers) {
            if ("RE".equals(emailReceiver.getReceiverType())) {
                to.append(";").append(emailReceiver.getReceiverAddress());
            }
            if ("CC".equals(emailReceiver.getReceiverType())) {
                toCc.append(";").append(emailReceiver.getReceiverAddress());
            }
        }
        if (StringUtils.isBlank(to.toString())) {
            throw new Exception("不存在主收件人，请联系管理员");
        }
        map.put("to", to.toString().substring(1));
        String tocc = StringUtils.isBlank(toCc.toString()) ? null : toCc.toString().substring(1);
        if (tocc != null) {
            map.put("toCc", tocc);
        }
        return map;
    }


    /**
     * 获取对象的字段信息
     *
     * @param emailInfo
     * @return
     */
    public Map<String, String> getObjField(EmailInfo emailInfo) throws Exception {
        Map<String, String> map = new HashMap<>();
        QueryParams qps = new QueryParams();
        qps.setPageFlag(false);
        qps.addFilter(new Filter("headId", emailInfo.getObjId()));
        qps.addFilter(new Filter("activeFlag", "Y"));
        AlertObjField t = (AlertObjField) BasicModel.transformClass(new AlertObjField(), qps);
        List<AlertObjField> alertObjFields = alertObjFieldService.queryByExamplePage(t);
        for (AlertObjField alertObjField : alertObjFields) {
            map.put(alertObjField.getFieldName(), alertObjField.getField());
        }
        return map;
    }

    /**
     * 生成邮件标题信息
     *
     * @param objInfo
     * @param fields
     * @param emailInfo
     * @return
     */
    public String genEmailTitle(List<Map<String, Object>> objInfo, Map<String, String> fields, EmailInfo emailInfo) {
        if (objInfo == null || objInfo.size() <= 0) {
            return emailInfo.getEmailTitle();
        }
        if (fields == null || fields.size() <= 0) {
            return emailInfo.getEmailTitle();
        }
        // 目前只支持单对象，不支持循环 所以只去第一条数据
        Map<String, Object> obj = objInfo.get(0);
        String title = emailInfo.getEmailTitle();
        for (String key : fields.keySet()) {
            title = repalce(title, "{" + key + "}", obj.get(fields.get(key)) == null ? "{未找到该字段内容}" : obj.get(fields.get(key)).toString());
        }
        return title;
    }

    /**
     * 生成邮件内容信息
     *
     * @param objInfo
     * @param fields
     * @param emailInfo
     * @return
     */
    public String genEmailContent(List<Map<String, Object>> objInfo, Map<String, String> fields, EmailInfo emailInfo) {
        if (objInfo == null || objInfo.size() <= 0) {
            return emailInfo.getEmailMsg();
        }
        if (fields == null || fields.size() <= 0) {
            return emailInfo.getEmailMsg();
        }
        // 目前只支持单对象，不支持循环 所以只去第一条数据
        Map<String, Object> obj = objInfo.get(0);
        String content = emailInfo.getEmailMsg();
        ;
        for (String key : fields.keySet()) {
            content = repalce(content, "{" + key + "}", obj.get(fields.get(key)) == null ? "{未找到该字段内容}" : obj.get(fields.get(key)).toString());
        }
        return content;
    }

    /**
     * 替换字符串
     *
     * @param str
     * @param searchString
     * @param replacement
     * @return
     */
    public static String repalce(String str, String searchString, String replacement) {
        return StringUtils.replace(str, searchString, replacement);
    }

    /**
     * 记录邮件发送记录
     *
     * @param emailInfo
     * @param emailReceiver
     * @param title
     * @param content
     * @param e
     */
    public void record(EmailInfo emailInfo, Map<String, String> emailReceiver, String title, String content, Exception e) throws Exception {
        EmailItem emailItem = new EmailItem();
        emailItem.setEmailId(emailInfo.getId());
        emailItem.setEmailReceiveAddr(emailReceiver.get("to"));
        emailItem.setEmailSendAddr(PropertyUtil.getCommonProperty("adress_bk"));
        emailItem.setSendedTime(DateUtil.dateToStr(new Date(), null));
        if (e == null) {
            emailItem.setStatus("发送成功");
        } else {
            emailItem.setStatus("发送失败");
            emailItem.setErrorMsg(e.getMessage());
        }
        if (emailInfo.getFilePaths() != null && emailInfo.getFilePaths().size() > 0) {
            emailItem.setAttachment(JSONObject.toJSONString(emailInfo.getFilePaths()));
        }
        emailItem.setEmailTitle(title);
        emailItem.setToCcAddress(emailReceiver.get("toCc"));
        emailItem.setEmailContent(content);
        emailItemService.insert(emailItem);
    }

    /**
     * 根据模板信息中的查找到适配请求对象id 查找到对应的请求地址以及请求参数等信息
     *
     * @param emailInfo
     * @return
     */
    public List<Map<String, Object>> getObjInfo(EmailInfo emailInfo,String token) throws Exception {
        AlertObjType alertObjType = alertObjTypeService.queryById(Long.valueOf(emailInfo.getObjId()));
        if (!"Y".equals(alertObjType.getTypeStatus())) {
            throw new Exception("设置模块插入对象已失效，请联系管理员");
        }

        String url = alertObjType.getObjPath();
        HttpHeaders headers = new HttpHeaders();
        token = SecurityInterceptor.internal_token.get();
        headers.add("INNERTOKEN", token);
        HttpEntity entity = new HttpEntity<Object>(emailInfo.getParams(), headers);
        ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.POST, entity, Map.class);

        if (response == null) {
            throw new Exception("获取参数信息失败");
        }
        HttpStatus status = response.getStatusCode();
        Map returnContent = new HashMap();
        List<Map<String, Object>> selectContent = new ArrayList<>();
        //判断状态码是否为2开头的
        if (status.is2xxSuccessful()) {
            returnContent = response.getBody();
            if ((boolean) returnContent.get("success")) {
                if (returnContent.get("result") == null) {
                    if (returnContent.get("rows") == null) {
                        selectContent = (List<Map<String, Object>>) returnContent.get("rows");
                    }
                } else {
                    Map<String, Object> map = (Map<String, Object>) returnContent.get("result");
                    selectContent.add(map);
                }
                return selectContent;
            } else {
                throw new Exception(returnContent.get("result") == null ? "" : returnContent.get("result").toString());
            }
        } else {
            throw new Exception("获取参数信息失败");
        }
    }
}
